#pragma once
#include <iostream>
#include <string>
#include <sys/socket.h>
#include <sys/epoll.h>
#include "Socket.hpp"
#include "Mutex.hpp"
#include "Log.hpp"
#include <memory>
#include <unistd.h>
#include <arpa/inet.h>

#define MAX 4096
using namespace SocketModule;
using namespace LockModule;
using namespace LogModule;
const int defaultfd = -1;
class EpollServer
{
public:
    EpollServer(int port)
        : _port(port), _listen_socket(std::make_unique<TcpSocket>()), _is_running(false), _epfd(defaultfd)
    {
    }

    void Recver(int fd)
    {
        char _recv_buf[1024];
        //报文完整性问题
        ssize_t n = recv(fd, _recv_buf, sizeof(_recv_buf), 0); // 此时读写就不会被阻塞了
        if (n > 0)
        {
            _recv_buf[n] = 0;
            LOG(LogLevel::INFO) << "recv from client" << "sockfd=" << fd << "msg=" << _recv_buf;
            // 回显给客户端
            std::string message = "Echo#";
            message += _recv_buf;
            send(fd, message.c_str(), message.size(), 0);
        }
        else if (n == 0)
        {
            LOG(LogLevel::INFO) << "client 正常退出 " << "sockfd=" << fd;
           
            //把fd移除要保证fd合法,所以是先移除再关闭
            int m = epoll_ctl(_epfd, EPOLL_CTL_DEL, fd, NULL);
            close(fd);
            if (m < 0)
            {
                LOG(LogLevel::ERROR) << "epoll_ctl error";
            }
            else
            {
                LOG(LogLevel::INFO) << "epoll_ctl success";
            }
        }
        else
        {
            LOG(LogLevel::ERROR) << "recv error" << "sockfd=" << fd;
          
            int m = epoll_ctl(_epfd, EPOLL_CTL_DEL, fd, NULL);
            close(fd);
            if (m < 0)
            {
                LOG(LogLevel::ERROR) << "epoll_ctl error";
            }
            else
            {
                LOG(LogLevel::INFO) << "epoll_ctl success";
            }
        }
    }
    void Accepter()
    {
        InetAddr client_addr;
        int client_sockfd = _listen_socket->Accept(&client_addr); // 这时就不会阻塞了
        if (client_sockfd < 0)
        {
            LOG(LogLevel::ERROR) << "accept error";
            return;
        }
        else
        {
            LOG(LogLevel::INFO) << "accept a client" << "new_sockfd=" << client_sockfd;
            // 此时不可以直接recv因为不确定对方有没有发数据，现在只是建立了链接
            // 所以继续select
            // 由于select返回结果会把那三个集合进行修改，所以每次调用select都要重新设置readfds这三个参数
            // 所以我们怎么知道要设置哪些文件描述符呢
            // 因此要设置一个新的集合，把历史的fd都保存起来，除非关闭了某个fd，否则一直保存着
            // 把这个新的fd交给epoll
            struct epoll_event ev;
            ev.data.fd = client_sockfd;
            ev.events = EPOLLIN;
            int n = epoll_ctl(_epfd, EPOLL_CTL_ADD, client_sockfd, &ev);
            if (n < 0)
            {
                LOG(LogLevel::ERROR) << "epoll_ctl error";
                close(client_sockfd);
            }
            else
            {
                LOG(LogLevel::INFO) << "epoll_ctl success";
            }
        }
    }
    void Dispatcher(int rnum) // n个就绪
    {
        for (int i = 0; i < rnum; i++)
        {
            int events = _ee[i].events;
            int fd = _ee[i].data.fd;
            if (fd == _listen_socket->Fd())
            {
                if (events & EPOLLIN)
                {
                    Accepter();
                }
            }
            else
            {
                if (events & EPOLLIN)
                {
                    // 进行读取
                    Recver(fd);
                }
                else if (events & EPOLLOUT)
                {
                    // 进行写入
                }
            }
        }
    }
    void Loop()
    {
        int timeout = -1;
        if (_is_running)
            return;
        _is_running = true;
        while (_is_running)
        {

            int n = epoll_wait(_epfd, _ee, MAX - 1, timeout);
            switch (n)
            {
            case -1:
                LOG(LogLevel::ERROR) << "epoll_wait error";
                break;
            case 0:
                LOG(LogLevel::DEBUG) << "epoll_wait timeout";
                break;
            default:
                LOG(LogLevel::DEBUG) << "epoll_wait success";
                Dispatcher(n);
                break;
            }
        }

        _is_running = false;
    }
    void Init()
    {
        _listen_socket->BuildTcpSocket(_port);
        _epfd = epoll_create(MAX);
        if (_epfd == -1)
        {
            LOG(LogLevel::FATAL) << "epoll_create error";
            exit(EPOLL_ERR);
        }
        LOG(LogLevel::INFO) << "epoll_create success" << "epfd=" << _epfd;
        // 添加listen_socket到epoll中
        struct epoll_event ev;
        ev.events = EPOLLIN;
        ev.data.fd = _listen_socket->Fd();
        int n = epoll_ctl(_epfd, EPOLL_CTL_ADD, ev.data.fd, &ev);
        if (n < 0)
        {
            LOG(LogLevel::FATAL) << "epoll_ctl error";
            exit(EPOLL_CTL_ERR);
        }
    }
    ~EpollServer()
    {
        if (_epfd != defaultfd)
            close(_epfd);
        _listen_socket->Close();
    }

private:
    uint16_t _port;
    std::unique_ptr<Socket> _listen_socket;
    bool _is_running;
    int _epfd;
    struct epoll_event _ee[MAX - 1];
};